package org.deltaset.meta.internal.mockmeta.web;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.deltaset.meta.EntityResolver;
import org.deltaset.meta.MetaAction;
import org.deltaset.meta.MetaActionHandler;
import org.deltaset.meta.MetaEntry;
import org.deltaset.meta.MetaField;
import org.deltaset.meta.OptionBuilder;
import org.deltaset.meta.TitleResolver;
import org.deltaset.meta.extension.MetaHandlerProvider;

/**
 *
 * @author dmakariev
 */
class SelectOptionBuilderImpl implements Serializable, OptionBuilder<SelectOption> {

    private final MetaHandlerProvider metaHandlerProvider;
    private final EntityResolver entityResolver;
    private final TitleResolver titleResolver;
    private Map<String, List<SelectOption>> cachedSelectOptions = new HashMap<String, List<SelectOption>>();

    SelectOptionBuilderImpl(
            final MetaHandlerProvider metaHandlerProvider,
            final EntityResolver entityResolver,
            final TitleResolver titleResolver) {
        this.metaHandlerProvider = metaHandlerProvider;
        this.entityResolver = entityResolver;
        this.titleResolver = titleResolver;
    }

    @Override
    public List<SelectOption> getOptions(final MetaField metaField) {
        final String cachedKey = selectOptionsKey(metaField);
        if (!cachedSelectOptions.containsKey(cachedKey)) {
            final List<SelectOption> options = prepareSelectOptions(metaField);
            cachedSelectOptions.put(cachedKey, options);
        }
        return cachedSelectOptions.get(cachedKey);
    }

    private List<SelectOption> prepareSelectOptions(final MetaField metaField) {
        final Class fieldClass = metaField.getOriginalType();
        final List<SelectOption> list = new ArrayList<SelectOption>();

        final List<Object> entities = loadSelectOptionValues(fieldClass);
        for (Object object : entities) {
            final Object value = prepareSelectValue(object);
            final String label = titleResolver.modelTitle(object);
            list.add(new SelectOption(value, label));
        }
        return list;
    }

    private List<Object> loadSelectOptionValues(final Class fieldClass) {
        final boolean isEnum = fieldClass.isEnum();
        final boolean isEntity = entityResolver.isEntity(fieldClass);//null != fieldClass.getAnnotation(Entity.class);
        if (true == isEnum) {
            return Arrays.asList(fieldClass.getEnumConstants());
        } else if (true == isEntity) {

           // final MetaHandler metaHandler = metaHandlerProvider.createMetaHandler(fieldClass);
            final MetaActionHandler metaActionHandler = metaHandlerProvider.createMetaActionHandler();
            final MetaEntry metaEntry = metaHandlerProvider.createMetaEntry(fieldClass);

            //final MetaClass fieldMetaClass = MetaClassFactory.forClass(fieldClass);
            //FIXME: this should use defaultLookUp or something similar..not defaultFinder
            final MetaAction defaultFinder = metaEntry.getDefaultFinder();//metaHandler.getDefaultFinder();//fieldMetaClass.getDefaultFinder();

            final List<Object> found = (List) metaActionHandler.executeAction(defaultFinder, null, new Object[]{0, 500});
            return found;
        } else {
            return Collections.emptyList();
        }
    }

    private Object prepareSelectValue(Object object) {
        final boolean isEnum = object.getClass().isEnum();
        if (true == isEnum) {
            return object;
        } else {
            //object should be entity here...
            final String valueKey = entityResolver.uniqueStringId(object);
            return cachedInViewScope(valueKey, object);
        }
    }

    private String selectOptionsKey(final MetaField metaField) {
        //TODO: might not be unique enough..
        final String prefix = metaField.getPropertyName() + "." + metaField.getPropertyType();
        return prefix;
        //return getClassName() + "." + metaField.getPropertyName();
    }

    private Object cachedInViewScope(String valueKey, Object object) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
